﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
using System.Diagnostics;

namespace BlackBox.Models
{
    public class WarriorsHub : Hub
    {
        #region Player Class
            public class Character
            {
                public string Name { get; set; }
                public string UserName { get; set; }
                public int HP { get; set; }
                public int Strength { get; set; }
                public int Dexterity { get; set; }
                public int Intelligence { get; set; }

                public string Class { get; set; }
                public string Race { get; set; }

                public string ConnectionId { get; set; }
            }
        #endregion

       
        GameRepository repGame = new GameRepository();
        UserRepository repUser = new UserRepository();

        //List of RegistedUsers
        static List<Character> RegistedUsers = new List<Character>();
        //List of Connected Users
        static List<string> ConnectedUsers = new List<string>();

        #region Tasks
        public override Task OnConnected()
        {
            //On Start
            if (ConnectedUsers.Count == 0)
            {
                ActiveGame theGame = new ActiveGame();
                theGame.owner = Context.User.Identity.Name.ToString();
                theGame.id = repGame.GetIdByOwner(theGame);
                theGame.numberofplayers = 1;
                repGame.Update(theGame);
            }
            else
            {
                //If the Owner has left
                if (ConnectedUsers[0] == null)
                {
                    return Clients.All.allThrow();
                }
                else 
                //Adding a Player
                {
                    ActiveGame theGame = new ActiveGame();
                    theGame.owner = ConnectedUsers[0];
                    theGame.id = repGame.GetIdByOwner(theGame);
                    theGame = repGame.GetActiveGameById(theGame.id);
                    theGame.numberofplayers += 1;
                    repGame.Update(theGame);
                }
            }
            //Adding to Conneted User list
            if (!ConnectedUsers.Contains(Context.User.Identity.Name.ToString()))
            {
                var player = RegistedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
                ConnectedUsers.Add(Context.User.Identity.Name.ToString());
            }
            Clients.All.register();
            return Clients.All.connected(Context.User.Identity.Name, ConnectedUsers);
        }

        public override Task OnDisconnected()
        {
            var deletePlayer = RegistedUsers.Where(x => x.ConnectionId == Context.ConnectionId).FirstOrDefault();
            //Removing from RegistedUsers list
            if (deletePlayer != null)
            {
                RegistedUsers.Remove(deletePlayer);
            }

            ActiveGame theGame = new ActiveGame();
            //Geting the Game id
                //If the list is not empty
            if (ConnectedUsers.Count != 0)
            {
                theGame.owner = ConnectedUsers[0];
                theGame.id = repGame.GetIdByOwner(theGame);

                //If the first User is not the owner
                if (theGame.id == -1)
                {
                    ConnectedUsers.Remove(Context.User.Identity.Name.ToString());
                    return Clients.All.disconnected(Context.User.Identity.Name);
                }
            }
            else
            {
                //Throw All out
                return Clients.All.allThrow();
            }

            //Removing the User
                //If the list is not empty
            if (ConnectedUsers.Count != 0)
            {
                //If the owner is the one that is disconecting
                if (ConnectedUsers[0] == Context.User.Identity.Name)
                {
                    repGame.RemoveActiveGame(theGame.id);
                    ConnectedUsers.Remove(Context.User.Identity.Name.ToString());
                    return Clients.All.allThrow();
                }
                else 
                //A player is disconecting
                {
                    theGame = repGame.GetActiveGameById(theGame.id);

                    theGame.numberofplayers -= 1;
                    repGame.Update(theGame);
                    ConnectedUsers.Remove(Context.User.Identity.Name.ToString());
                    return Clients.All.disconnected(Context.User.Identity.Name);
                }
            }
            else 
            //This should never happen (So all paths retun a value)
            {
                repGame.RemoveActiveGame(theGame.id);
                ConnectedUsers.Remove(Context.User.Identity.Name.ToString());
                return Clients.All.allThrow();
            }
        }
        #endregion

        #region General

            #region Register Client
                //Registering the Client and making a sheet
                public void RegisterClient()
                {
                    if (RegistedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId) == null)
                    {
                        //If the User is not the Owner
                        if(Context.User.Identity.Name != ConnectedUsers[0])
                        {
                            Character Character = new Character();
                            {
                                Random random = new Random(DateTime.Now.Millisecond);

                                Character.UserName = Context.User.Identity.Name;

                                int results = random.Next(1, 3);

                                if (results == 1)
                                {
                                    Character.Race = "Human";
                                    Character.Name = "The Greate One";

                                    results = random.Next(1, 1);
                                    if (results == 1)
                                    {
                                        Character.Class = "Warrior";
                                    }
                                }

                                if (results == 2)
                                {
                                    Character.Race = "Orc";
                                    Character.Name = "Killer Orc";
                                    results = random.Next(1, 1);
                                    if (results == 1)
                                    {
                                        Character.Class = "Warrior";
                                    }
                                }

                                Character.HP = random.Next(10, 51);
                                Character.Strength = random.Next(3, 11);
                                Character.Intelligence = random.Next(3, 11);
                                Character.Dexterity = random.Next(3, 11);

                                Character.ConnectionId = Context.ConnectionId;
                            };
                            RegistedUsers.Add(Character);
                            Clients.All.registerDone(Character.UserName);
                        }
                        else
                        //If the User is the Owner then he is gets a special sheet
                        {
                            Character MasterCharacter = new Character();
                            {
                                MasterCharacter.UserName = Context.User.Identity.Name;
                                MasterCharacter.ConnectionId = Context.ConnectionId;
                            };
                            RegistedUsers.Add(MasterCharacter);
                            Clients.All.registerDone(MasterCharacter.UserName);
                        }
                    }
                }
                #endregion

            #region Start Game

                //If there are 2 players our more the game will start
                public void StartGame()
                {
                    var player = RegistedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);

                    //If you are not foudn in the Registered list
                    if (player == null)
                        return;

                    var opponent = RegistedUsers.Where(x => x.ConnectionId != Context.ConnectionId).FirstOrDefault();

                    //If a opponent is not found in the Registered list
                    if (opponent == null)
                    {
                        Clients.Client(Context.ConnectionId).testStart(false);
                        return;
                    }
                    else
                    {
                        Clients.Client(Context.ConnectionId).testStart(true);
                    }
                }
            #endregion
            
            #region Load Game
                //Loads Game and Sheets
                public void LoadGame()
                {
                    Clients.All.InsertGame();
                    Clients.All.CallSheets();
                }   
            #endregion
        #endregion

        #region Chat
            #region SendMessage (Menu)
            //Sends a message to all users (Menu)
            public void SendMessage(string message)
            {
                string from = Context.User.Identity.Name;
                Clients.All.AddMessage(from, message);
            }
            #endregion

            #region Game Message (Game)
            //Sends a message to all users (Game)
            public void GameMessage(string message)
            {
                string User = Context.User.Identity.Name;

                var CharUser = RegistedUsers.Where(x => x.UserName == User).SingleOrDefault();

                //If the user us the owner he is the "Dungeon Master"
                if (ConnectedUsers[0] == User)
                {
                    Clients.All.AddAdminMessage("Dungeon Master", message);
                }
                else
                {
                    Clients.All.AddGameMessage(CharUser.Name, message);
                }
            }
            #endregion 

            #region Send Message (Owner)
            //Only Master
            public void OnlyMaster(string message)
            {
                string from = Context.User.Identity.Name;
                Clients.All.AddMasterMessage(from, message);
            }
            #endregion
        #endregion

        #region Game functions

        #region Dice
        //Dice that rolls a random number 1-20
        public void Dice()
        {
            Random random = new Random(DateTime.Now.Millisecond);

            int results = random.Next(1, 21);

            string from = Context.User.Identity.Name;

            var Char = RegistedUsers.Where(x => x.UserName == from).FirstOrDefault();

            if (ConnectedUsers[0] == from)
            {
                Clients.All.ShowDice("Dungeon master", results);
            }
            else
            {
                Clients.All.ShowDice(Char.Name, results);
            }
        }
        #endregion

        #region Kill PLayer
        //Kills a player
        public void Kill(string name)
        {
            var kill = RegistedUsers.Where(x => x.UserName == name).SingleOrDefault();

                if (kill == null)
                {
                    Clients.Client(Context.ConnectionId).Alert("Player Not Found");
                }
                else
                {
                    RegistedUsers.Remove(kill);
                    ConnectedUsers.Remove(Context.User.Identity.Name.ToString());
                    Clients.Client(kill.ConnectionId).allThrow();
                }
        }
        #endregion 

        #region Add Sheet (DOM)
        //Add Sheet to DOM
        public void AddSheet()
        {
            var me = RegistedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
            if (me != null)
            {
                if (ConnectedUsers[0] != me.UserName)
                {
                    Clients.Client(me.ConnectionId).loadSheet(me.HP, me.Strength, me.Intelligence,
                                                        me.Dexterity, me.Class, me.Race, me.Name);
                }
                else
                {
                    Clients.Client(me.ConnectionId).loadMasterSheet(me.UserName);
                }
            }
        }
        #endregion

        #region Command Box
        //A CommandBox (Can remove HP and spawn Monsters)
        public void CommandBox(string name, int newHP)
        {
            var player = RegistedUsers.Where(x => x.UserName == name).SingleOrDefault();

            if (player == null)
            {
                if (name != null)
                {
                    Random random = new Random(DateTime.Now.Millisecond);

                    int dmg = random.Next(1, 9);

                    string message = name + " attacks and does " + dmg + " in damages(" + newHP +" left)";
                    Clients.All.addGameAction(message);
                }
                Clients.Client(Context.ConnectionId).Alert("Command Failed");
            }
            else
            {
                player.HP = newHP;
                Clients.Client(player.ConnectionId).editHP(newHP);
            }
        }
        #endregion

        #region Action 
        //Action (Attack, Run)
        public void Action(string action)
        {
            var Char = RegistedUsers.Where(x => x.UserName == Context.User.Identity.Name).SingleOrDefault();

            if (Char != null)
            {
                string message = Char.Name + " " + action;

                Clients.All.addGameAction(message);
            }
            else
            {
                string alert = "An Error an Occurred";
                Clients.Client(Context.ConnectionId).Alert(alert);
            }
        }

        #endregion

        #endregion
    }
}